using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Web;
using System.Linq;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using ezCloud.Api.Models;
using ezCloud.Api.Providers;
using ezCloud.Api.Results;
using ezCloud.Data;
using System.Configuration;
using System.Net;
using ezCloud.Api.Services;
using Microsoft.Owin.Testing;
using System.Web.Script.Serialization;
using System.IO;
using Microsoft.Owin.Security.Infrastructure;
using ezCloud.Api.Common;
using Newtonsoft.Json;

namespace ezCloud.Api.Controllers
{
    [Authorize]
    [RoutePrefix("api/Account")]

    public class AccountController : ezController
    {
        private const string LocalLoginProvider = "Local";
        private ApplicationUserManager _userManager;

        public AccountController()
        {
        }

        public AccountController(ApplicationUserManager userManager,
            ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
        {
            UserManager = userManager;
            AccessTokenFormat = accessTokenFormat;
        }

        public ApplicationUserManager UserManager
        {
            get
            {
                return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
            }
            private set
            {
                _userManager = value;
            }
        }

        public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }

        // GET api/Account/UserInfo
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("UserInfo")]
        public async Task<IHttpActionResult> GetUserInfo()
        {

            var userIdentity = (ClaimsIdentity)User.Identity;
            var roles = userIdentity.Claims
                       .Where(c => c.Type == ClaimTypes.Role)
                       .Select(c => c.Value)
                       .ToList();

            return Ok(new
            {
                Email = User.Identity.GetUserName(),
                Roles = roles.Aggregate((i, j) => i + "," + j),
            });
        }
        /*[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("StartSession")]
        public async Task<IHttpActionResult> GetStartSession()
        {

            var userSession = new Common.UserSessionManager();
            userSession.CreateUserSession(User.Identity.Name);

            return Ok();
        }*/
        /*
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("StartSession")]
        public async Task<IHttpActionResult> GetStartSession(string oldToken)
        {

            var userSession = new Common.UserSessionManager();
            userSession.CreateUserSession(User.Identity.Name);
            userSession.InvalidateUserSession(oldToken);

            return Ok();
        }*/

        // POST api/Account/Logout
        [Route("Logout")]
        public async Task<IHttpActionResult> Logout(setLogout model)
        {
            var user = Common.UserUtitily.getUserProfile();
            //Notification.sendNotificationToDevice( user.UserName.ToLower() , "See you again!", 103, "NOTIFICATION_CHECKEDIN");

            Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
            var userSessionManager = new Common.UserSessionManager();
            userSessionManager.InvalidateUserSession();
            //return StatusCode(System.Net.HttpStatusCode.BadRequest);
            try
            {
                Notification.EjectDevice(model.NotificationToken);
            }
            catch (Exception ex)
            {

            }

            return Ok();
        }
        [HttpGet]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("SetNotification")]
        public async Task<IHttpActionResult> SetNotification(string token, string type)
        {
            var user = Common.UserUtitily.getUserProfile();
            Notification.addNotificationToken(user.UserName, token, type);
            return Ok();
        }

        // GET api/Account/ManageInfo?returnUrl=%2F&generateState=true
        [Route("ManageInfo")]
        public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
        {
            IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());

            if (user == null)
            {
                return null;
            }

            List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();

            foreach (IdentityUserLogin linkedAccount in user.Logins)
            {
                logins.Add(new UserLoginInfoViewModel
                {
                    LoginProvider = linkedAccount.LoginProvider,
                    ProviderKey = linkedAccount.ProviderKey
                });
            }

            if (user.PasswordHash != null)
            {
                logins.Add(new UserLoginInfoViewModel
                {
                    LoginProvider = LocalLoginProvider,
                    ProviderKey = user.UserName,
                });
            }

            return new ManageInfoViewModel
            {
                LocalLoginProvider = LocalLoginProvider,
                Email = user.UserName,
                Logins = logins,
                ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
            };
        }

        #region Password
        // POST api/Account/ChangePassword
        [Route("ChangePassword")]
        public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var currentClientUser = Common.UserUtitily.getUserProfile();

            IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
                model.NewPasswordConfirm);
            //await UserManager.UpdateSecurityStampAsync(User.Identity.GetUserId());
            Providers.SimpleRefreshTokenProvider.InvalidateUser(User.Identity.Name);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            UserSessionManager usm = new UserSessionManager();
            usm.SignOutUserId(User.Identity.GetUserId());

            return Ok();
        }

        // POST api/Account/SetPassword
        [Route("SetPassword")]
        public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        [AllowAnonymous]
        [Route("SignOutUser")]
        [HttpGet]
        public async Task<IHttpActionResult> SignOutUser(string id)
        {
            if (!InternalServices.isAllowed()) { return BadRequest("IP_NOT_ALLOW_EXIST:" + HttpContext.Current.Request.UserHostAddress); };
            UserSessionManager usm = new UserSessionManager();
            usm.SignOutUserId(id);
            return Ok();
        }
        // POST: /Account/ForgotPassword
        [AllowAnonymous]
        [Route("ForgotPassword")]
        public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Random rnd = new Random();

            //EmailService emailService = new EmailService();
            //IdentityMessage message = new IdentityMessage();
            //message.Destination = model.Email;
            //message.Subject = "ezCloud Hotel - Khởi tạo lại mật khẩu";
            string subject= "ezCloud Hotel - Reset password / Khởi tạo lại mật khẩu";

            //var user = await UserManager.FindByNameAsync(email);

            if (model.Role == "ROLE_HOTEL_OWNER")
            {
                var user = UserManager.FindByEmail(model.Email);

                if (user == null || !(UserManager.IsEmailConfirmed(user.Id)))
                {
                    ModelState.AddModelError("Message", "THE_EMAIL_ACCOUNT_THAT_YOU_TRIED_TO_REACH_DOES_NOT_EXIST_OR_CONFIRMED.");
                    return BadRequest(ModelState);
                }


                var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
                code = System.Web.HttpUtility.UrlEncode(code).Replace("%2", "%252");
                var hotelOwner = context.HotelOwners.FirstOrDefault(ho => ho.UserId == user.Id);
                user.EmailConfirmToken = code;
                //await UserManager.UpdateAsync(user);
                var callbackUrl = ConfigurationManager.AppSettings["RootUrl"] + "#/ResetPassword/" + user.Id + "/" + user.Email + "/" + code;
                //string emailTemplate = File.ReadAllText(HttpContext.Current.Server.MapPath("/EmailTemplates/emailResetPassword.html"));
                //emailTemplate = emailTemplate.Replace("{{Fullname}}", (hotelOwner == null) ? user.Email : hotelOwner.FullName).Replace("{{ConfirmationLink}}", callbackUrl);
                //message.Body = emailTemplate;

                //emailService.SendGmailAsync(message);

                EmailSender.SendEmailResetPassword(model.Email, subject, (hotelOwner == null) ? user.Email : hotelOwner.FullName, callbackUrl);
            }
            else
            {
                var staff = context.Staffs.Where(stf => stf.Email == model.Email && stf.HotelId == model.HotelId).FirstOrDefault();
                if (staff == null)
                {
                    ModelState.AddModelError("Message", "STAFF_DOSE_NOT_EXIST");
                    return BadRequest(ModelState);
                }
                else
                {
                    var user = UserManager.FindById(staff.UserId);
                    if (user == null)
                    {
                        ModelState.AddModelError("Message", "STAFF_DOES_NOT_EXIST");
                        return BadRequest(ModelState);
                    }
                    var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
                    code = System.Web.HttpUtility.UrlEncode(code).Replace("%2", "%252");
                    user.EmailConfirmToken = code;
                    await UserManager.UpdateAsync(user);
                    var callbackUrl = ConfigurationManager.AppSettings["RootUrl"] + "/#/ResetPassword/" + user.Id + "/" + model.Email + "/" + code;
                    //string emailTemplate = File.ReadAllText(HttpContext.Current.Server.MapPath("/EmailTemplates/emailResetPassword.html"));
                    //emailTemplate = emailTemplate.Replace("{{Fullname}}", staff.StaffName).Replace("{{ConfirmationLink}}", callbackUrl);
                    //message.Body = emailTemplate;
                    //emailService.SendGmailAsync(message);

                    EmailSender.SendEmailResetPassword(model.Email, subject, staff.StaffName, callbackUrl);
                }
            }
            return Ok();
        }

        [HttpPost]
        [AllowAnonymous]
        [Route("ResetPassword")]
        public async Task<IHttpActionResult> ResetPassword(ResetPasswordViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }


            //var user = await UserManager.FindByNameAsync(email);
            var user = UserManager.FindById(model.UserId);
            //var staff = context.Staffs.Where(stf => stf.Email == email).FirstOrDefault();
            //var user = await UserManager.FindByNameAsync(model.Email);
            if (user == null)
            {
                ModelState.AddModelError("Message", "USER_NOT_FOUND");
                return BadRequest(ModelState);
            }
            model.Code = HttpContext.Current.Server.UrlDecode(model.Code);
            var success = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);

            if (success.Succeeded)
            {
                UserSessionManager usm = new UserSessionManager();
                usm.SignOutUserId(user.Id);

                return Ok();
            }
            else {
                ModelState.AddModelError("Message", "INVALID_CONFIRM_TOKEN");
                return BadRequest(ModelState);
            }
        }
        #endregion
        #region ExternalLogin

        // POST api/Account/AddExternalLogin
        [Route("AddExternalLogin")]
        public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

            AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);

            if (ticket == null || ticket.Identity == null || (ticket.Properties != null
                && ticket.Properties.ExpiresUtc.HasValue
                && ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
            {
                return BadRequest("External login failure.");
            }

            ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);

            if (externalData == null)
            {
                return BadRequest("The external login is already associated with an account.");
            }

            IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
                new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // POST api/Account/RemoveLogin
        [Route("RemoveLogin")]
        public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            IdentityResult result;

            if (model.LoginProvider == LocalLoginProvider)
            {
                result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
            }
            else
            {
                result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
                    new UserLoginInfo(model.LoginProvider, model.ProviderKey));
            }

            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            return Ok();
        }

        // GET api/Account/ExternalLogin
        [OverrideAuthentication]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
        [AllowAnonymous]
        [Route("ExternalLogin", Name = "ExternalLogin")]
        public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
        {
            if (error != null)
            {
                return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
            }

            if (!User.Identity.IsAuthenticated)
            {
                return new ChallengeResult(provider, this);
            }

            ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);

            if (externalLogin == null)
            {
                return InternalServerError();
            }

            if (externalLogin.LoginProvider != provider)
            {
                Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
                return new ChallengeResult(provider, this);
            }

            ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
                externalLogin.ProviderKey));

            bool hasRegistered = user != null;

            if (hasRegistered)
            {
                Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

                ClaimsIdentity oAuthIdentity = await UserManager.CreateIdentityAsync(user,
                OAuthDefaults.AuthenticationType);
                AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.Id.ToString());
                var ticket = new AuthenticationTicket(oAuthIdentity, properties);
                await Startup.OAuthOptions.RefreshTokenProvider.CreateAsync(new AuthenticationTokenCreateContext(Request.GetOwinContext(), Startup.OAuthOptions.RefreshTokenFormat, ticket));
                Authentication.SignIn(properties, oAuthIdentity);
            }
            else
            {
                //Email look up first
                user = await UserManager.FindByNameAsync(externalLogin.Email);
                if (user != null)
                {
                    IdentityResult result = await UserManager.AddLoginAsync(user.Id,
                new UserLoginInfo(externalLogin.LoginProvider, externalLogin.ProviderKey));
                    if (result.Succeeded)
                    {
                        Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

                        ClaimsIdentity oAuthIdentity = await UserManager.CreateIdentityAsync(user,
        OAuthDefaults.AuthenticationType);
                        AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.Id.ToString());
                        var ticket = new AuthenticationTicket(oAuthIdentity, properties);
                        await Startup.OAuthOptions.RefreshTokenProvider.CreateAsync(new AuthenticationTokenCreateContext(Request.GetOwinContext(), Startup.OAuthOptions.RefreshTokenFormat, ticket));
                        Authentication.SignIn(properties, oAuthIdentity);
                    }
                    else
                    {
                        IEnumerable<Claim> claims = externalLogin.GetClaims();
                        ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
                        Authentication.SignIn(identity);
                    }
                }
                else
                {
                    IEnumerable<Claim> claims = externalLogin.GetClaims();
                    ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
                    Authentication.SignIn(identity);
                }


            }


            return Ok();
        }

        // GET api/Account/ExternalLogins?returnUrl=%2F&generateState=true
        [AllowAnonymous]
        [Route("ExternalLogins")]
        public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
        {
            IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
            List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();

            string state;

            if (generateState)
            {
                const int strengthInBits = 256;
                state = RandomOAuthStateGenerator.Generate(strengthInBits);
            }
            else
            {
                state = null;
            }

            foreach (AuthenticationDescription description in descriptions)
            {
                ExternalLoginViewModel login = new ExternalLoginViewModel
                {
                    Name = description.Caption,
                    Url = Url.Route("ExternalLogin", new
                    {
                        provider = description.AuthenticationType,
                        response_type = "token",
                        client_id = Startup.PublicClientId,
                        redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
                        state = state
                    }),
                    State = state
                };
                logins.Add(login);
            }

            return logins;
        }
        #endregion

        // POST api/Account/Register
        [AllowAnonymous]
        [Route("Register")]
        public async Task<IHttpActionResult> Register(RegisterViewModel model)
        {
            /*if (!ModelState.IsValid)
            {
                var errors = new List<string>();
                foreach (var state in ModelState)
                {
                    foreach (var error in state.Value.Errors)
                    {
                        errors.Add(error.ErrorMessage);
                        ModelState.AddModelError("email_invalid",error.ErrorMessage);
                    }
                }
               
            }*/
            var loginInfo = Authentication.GetExternalLoginInfo();
            if (loginInfo != null)
            {
                model.Email = loginInfo.Email;
            }
            bool captchaVerify = Common.reCaptcha.Validate(model.CaptchaCode); //Controllers.CaptchaController.CaptchaVerify(model.CaptchaId, model.CaptchaCode);
            if (!captchaVerify)
            {

                //return BadRequest("INVALID_CAPTCHA");
                ModelState.AddModelError("captcha_invalid", "INCORRECT_CAPTCHA");
                return BadRequest(ModelState);
            }
            if (!ModelState.IsValid)
            {
                //ModelState.AddModelError("email_invalid","EMAIL_IS_ALREADY_TAKEN");
                return BadRequest(ModelState);
            }

            var user = new ApplicationUser()
            {
                UserName = model.Email,
                Email = model.Email
            };

            // user.PhoneNumber = model.PhoneNumber;




            IdentityResult result = UserManager.Create(user, model.Password);

            if (!result.Succeeded)
            {
                //return GetErrorResult(result);
                ModelState.AddModelError("email_invalid", "EMAIL_IS_ALREADY_TAKEN");
                return BadRequest(ModelState);
            }


            if (loginInfo == null)
            {
                Random rnd = new Random();
                EmailService emailService = new EmailService();
                //user.EmailConfirmToken = rnd.Next(100000, 999999).ToString();
                var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                code = System.Web.HttpUtility.UrlEncode(code).Replace("%2", "%252");
                user.RegistrationDate = DateTime.UtcNow;
                UserManager.AddToRole(user.Id, "ROLE_HOTEL_OWNER");
                UserManager.Update(user);

                var callbackUrl = ConfigurationManager.AppSettings["RootUrl"] + "#/ConfirmEmail/" + user.Id + "/" + code;

                
                //IdentityMessage message = new IdentityMessage();
                //message.Destination = model.Email;
                //string emailTemplate = File.ReadAllText(HttpContext.Current.Server.MapPath("/EmailTemplates/emailConfirmation.html"));
                //emailTemplate = emailTemplate.Replace("{{Fullname}}", model.HotelOwnerFullName).Replace("{{Username}}", model.Email).Replace("{{Password}}", model.Password).Replace("{{ConfirmationLink}}", callbackUrl);
                //message.Body = emailTemplate;
                //message.Subject = "ezCloud Hotel - XÁC THỰC TÀI KHOẢN";
                //emailService.SendGmailAsync(message);
                string subject = "ezCloud Hotel - Confirmation / XÁC THỰC TÀI KHOẢN";
                EmailSender.SendEmailConfirmation(model.Email, model.Password, subject, model.Email, callbackUrl);

            }
            else
            {
                user.RegistrationDate = DateTime.UtcNow;
                UserManager.AddToRole(user.Id, "ROLE_HOTEL_OWNER");
                user.EmailConfirmed = true;
                await UserManager.UpdateAsync(user);
            }



            HotelOwners hotelOwner = new Data.HotelOwners();
            hotelOwner.UserId = user.Id;
            hotelOwner.FullName = model.HotelOwnerFullName;
            hotelOwner.Address = model.HotelOwnerAddress;
            hotelOwner.Phone = model.HotelOwnerPhoneNumber;
            hotelOwner.IsActive = true;

            hotelOwner.NumberOfHotels = model.NumberOfHotels ?? default(int);
            hotelOwner.HotelSizeId = model.HotelSizeId ?? default(int);

            context.HotelOwners.InsertOnSubmit(hotelOwner);
            context.SubmitChanges();

            return Ok();

        }


        // POST api/Account/RegisterExternal
        [OverrideAuthentication]
        [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
        [Route("RegisterExternal")]
        public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var info = await Authentication.GetExternalLoginInfoAsync();
            if (info == null)
            {
                return InternalServerError();
            }
            var externalIdentity = Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
            var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);

            var user = new ApplicationUser()
            {
                Email = model.Email
            };

            IdentityResult result = await UserManager.CreateAsync(user);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            result = await UserManager.AddLoginAsync(user.Id, info.Login);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }
            return Ok();
        }

        [HttpPost]
        [AllowAnonymous]
        [Route("Login")]
        public async Task<IHttpActionResult> LoginUser(LoginUserBindingModel model)
        {
            if (model == null)
            {
                return this.BadRequest("Invalid user data");
            }

            // Invoke the "token" OWIN service to perform the login (POST /api/token)
            // Use Microsoft.Owin.Testing.TestServer to perform in-memory HTTP POST request
            var testServer = TestServer.Create<Startup>();
            var isAdmin = false;
            if (model.HotelId != null && model.HotelId != 0)
            {
                var adminAccounts = ConfigurationSettings.AppSettings["adminAccounts"];
                if (adminAccounts != null)
                {
                    if (adminAccounts.IndexOf(model.Username.ToLower()) >= 0)
                    {
                        //admin account
                        isAdmin = true;
                    }
                }
            }
            var requestParams = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "password"),
                new KeyValuePair<string, string>("username", model.Username),
                new KeyValuePair<string, string>("password", model.Password),
                new KeyValuePair<string, string>("client_id", "ezCloud"),
                new KeyValuePair<string, string>("client_secret", "secret"),

            };
            if (isAdmin)
            {
                requestParams.Add(new KeyValuePair<string, string>("hotelId", model.HotelId.ToString()));
            }
            var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
            var tokenServiceResponse = await testServer.HttpClient.PostAsync(
                Startup.TokenEndpointPath, requestParamsFormUrlEncoded);
            
            if (tokenServiceResponse.StatusCode == HttpStatusCode.OK)
            {

                // Sucessful login --> create user session in the database
                var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
                var jsSerializer = new JavaScriptSerializer();
                var responseData =
                    jsSerializer.Deserialize<Dictionary<string, string>>(responseString);
                var authToken = responseData["access_token"];
                //var username = responseData["userName"];
                var username = model.Username;
                var userSessionManager = new Common.UserSessionManager();
                userSessionManager.CreateUserSession(username, authToken);

                // Cleanup: delete expired sessions fromthe database
                userSessionManager.DeleteExpiredSessions();

                Notification.addNotificationToken(model.Username.ToLower(), model.NotificationToken, model.NotificationType);
                //Notification.sendNotificationToDevice(model.Username.ToLower(), "well come to ezcloudhotel", model.HotelId, "NOTIFICATION_CHECKEDIN");
                //Notification.sendNotificationToDevice(model.Username.ToLower(), "well come to ezcloudhotel 2");
            }

            return this.ResponseMessage(tokenServiceResponse);

        }
        [HttpPost]
        [AllowAnonymous]
        [Route("Refresh")]
        public async Task<IHttpActionResult> RefreshToken(RefreshModel model)
        {
            if (model == null)
            {
                return this.BadRequest("Invalid user data");
            }

            // Invoke the "token" OWIN service to perform the login (POST /api/token)
            // Use Microsoft.Owin.Testing.TestServer to perform in-memory HTTP POST request
            var testServer = TestServer.Create<Startup>();
            var requestParams = new List<KeyValuePair<string, string>>
            {
                new KeyValuePair<string, string>("grant_type", "refresh_token"),
                new KeyValuePair<string, string>("refresh_token", model.refresh_token),
                new KeyValuePair<string, string>("client_id", "ezCloud"),
                new KeyValuePair<string, string>("client_secret", "secret")
            };
            var requestParamsFormUrlEncoded = new FormUrlEncodedContent(requestParams);
            var tokenServiceResponse = await testServer.HttpClient.PostAsync(
                Startup.TokenEndpointPath, requestParamsFormUrlEncoded);

            if (tokenServiceResponse.StatusCode == HttpStatusCode.OK)
            {
                // Sucessful login --> create user session in the database
                var responseString = await tokenServiceResponse.Content.ReadAsStringAsync();
                var jsSerializer = new JavaScriptSerializer();
                var responseData =
                    jsSerializer.Deserialize<Dictionary<string, string>>(responseString);
                var authToken = responseData["access_token"];
                var username = responseData["userName"];
                var userSessionManager = new Common.UserSessionManager();
                userSessionManager.InvalidateUserSession();
                userSessionManager.CreateUserSession(username, authToken);

                // Cleanup: delete expired sessions fromthe database
                userSessionManager.DeleteExpiredSessions();
            }

            return this.ResponseMessage(tokenServiceResponse);
        }

        [AllowAnonymous]
        [Route("ConfirmEmail")]
        public async Task<IHttpActionResult> ConfirmEmail(ConfirmEmailViewModel model)
        {
            var user = await UserManager.FindByIdAsync(model.UserId);
            if (model.UserId == null || model.Code == null || user == null)
            {
                return BadRequest(ModelState);
            }

            model.Code = HttpUtility.UrlDecode(model.Code);
            var result = await UserManager.ConfirmEmailAsync(model.UserId, model.Code);
            if (result.Succeeded)
            {
                user.EmailConfirmed = true;
                user.EmailConfirmedDate = DateTime.UtcNow;
                await UserManager.UpdateAsync(user);
                return Ok();
            }
            else
                return NotFound();
        }


        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                UserManager.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Helpers

        [HttpGet]
        [Route("EmailAvailable")]
        public bool EmailAvailable(string email)
        {
            bool result = false;
            var temp = UserManager.FindByEmail(email);
            if (temp != null)
            {
                result = true;
            }
            return result;
        }


        private IAuthenticationManager Authentication
        {
            get { return Request.GetOwinContext().Authentication; }
        }

        private IHttpActionResult GetErrorResult(IdentityResult result)
        {
            if (result == null)
            {
                return InternalServerError();
            }

            if (!result.Succeeded)
            {
                if (result.Errors != null)
                {
                    foreach (string error in result.Errors)
                    {
                        ModelState.AddModelError("", error);
                    }


                    if (ModelState.IsValid)
                    {
                        // No ModelState errors are available to send, so just return an empty BadRequest.
                        return BadRequest();
                    }

                    return BadRequest(ModelState);
                }
            }
            return null;
        }



        private class ExternalLoginData
        {
            public string LoginProvider { get; set; }
            public string ProviderKey { get; set; }
            public string UserName { get; set; }
            public string Email { get; set; }

            public IList<Claim> GetClaims()
            {
                IList<Claim> claims = new List<Claim>();
                claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));

                if (UserName != null)
                {
                    claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
                }
                if (!String.IsNullOrEmpty(Email))
                {
                    claims.Add(new Claim(ClaimTypes.Email, Email, null, LoginProvider));
                }

                return claims;
            }

            public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
            {
                if (identity == null)
                {
                    return null;
                }
                string userEmail = string.Empty;
                Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
                Claim emailDetails = identity.FindFirst(ClaimTypes.Email);
                if (emailDetails != null) userEmail = emailDetails.Value;

                if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
                    || String.IsNullOrEmpty(providerKeyClaim.Value))
                {
                    return null;
                }

                if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
                {
                    return null;
                }

                return new ExternalLoginData
                {
                    LoginProvider = providerKeyClaim.Issuer,
                    ProviderKey = providerKeyClaim.Value,
                    UserName = identity.FindFirstValue(ClaimTypes.Name),
                    Email = userEmail
                };
            }
        }

        private static class RandomOAuthStateGenerator
        {
            private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();

            public static string Generate(int strengthInBits)
            {
                const int bitsPerByte = 8;

                if (strengthInBits % bitsPerByte != 0)
                {
                    throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
                }

                int strengthInBytes = strengthInBits / bitsPerByte;

                byte[] data = new byte[strengthInBytes];
                _random.GetBytes(data);
                return HttpServerUtility.UrlTokenEncode(data);
            }
        }

        #endregion 
        [HttpGet]
        [AllowAnonymous]
        [Route("getnotification")]
        public async Task<IHttpActionResult> getMesssage(String uid, int size, int from)
        {
           
            var user = UserUtitily.getUserProfile();
            uid = user.UserName;
            //if (uid != null)
            //{
            using (var client = new HttpClient())
            {
                // New code:
                client.BaseAddress = new Uri(ConfigurationManager.AppSettings["notification_server"]);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.TryAddWithoutValidation("Authorization", "key=" + ConfigurationManager.AppSettings["notification_server_key"]);

                var postData = new
                {
                    uid = uid,
                    size = size,
                    from = from
                };
                HttpResponseMessage response = await client.PostAsJsonAsync("messages/" + ConfigurationManager.AppSettings["notification_server_clientid"], postData);
                if (response.IsSuccessStatusCode)
                {
                    var jsonString = response.Content.ReadAsStringAsync();
                    jsonString.Wait();
                    return Ok(new { noti = JsonConvert.DeserializeObject(jsonString.Result) });
                }

                return null;
            }
            //}

            return BadRequest("error");
        }
    }




}
